#import <Foundation/Foundation.h>
#include <AssertMacros.h>
#include <Security/SecureTransportPriv.h> /* SSLSetOption */
#include <Security/SecureTransport.h>
#include <utilities/SecCFRelease.h>
#include <Security/SecCertificatePriv.h>

#import "STLegacyTests.h"
static unsigned char cert_der[] = {
    0x30, 0x82, 0x02, 0x79, 0x30, 0x82, 0x02, 0x23, 0xa0, 0x03, 0x02, 0x01,
    0x02, 0x02, 0x09, 0x00, 0xc2, 0xa8, 0x3b, 0xaa, 0x40, 0xa4, 0x29, 0x2b,
    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
    0x05, 0x05, 0x00, 0x30, 0x5e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
    0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
    0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49,
    0x6e, 0x63, 0x2e, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b,
    0x13, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74,
    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06,
    0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68,
    0x6f, 0x73, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x39, 0x31,
    0x35, 0x32, 0x31, 0x35, 0x30, 0x35, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x39,
    0x30, 0x39, 0x31, 0x35, 0x32, 0x31, 0x35, 0x30, 0x35, 0x36, 0x5a, 0x30,
    0x5e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
    0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
    0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
    0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, 0x70,
    0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
    0x69, 0x74, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03,
    0x13, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30,
    0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
    0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00,
    0xc0, 0x80, 0x43, 0xf1, 0x4d, 0xdc, 0x9a, 0x24, 0xe7, 0x25, 0x7c, 0x8b,
    0x8b, 0x65, 0x87, 0x97, 0xed, 0x3f, 0xfa, 0xfe, 0xbe, 0xcb, 0x12, 0x43,
    0x1f, 0x0c, 0xb5, 0xbf, 0x6b, 0x81, 0xee, 0x1b, 0x46, 0x6a, 0x02, 0x86,
    0x92, 0xec, 0x8a, 0xb3, 0x65, 0x77, 0x15, 0xd0, 0x49, 0xb4, 0x22, 0x84,
    0xf4, 0x85, 0x56, 0x53, 0xf5, 0x5a, 0x3b, 0xad, 0x23, 0xa8, 0x0c, 0x24,
    0xb7, 0xf5, 0xf4, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xc3,
    0x30, 0x81, 0xc0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
    0x04, 0x14, 0xe3, 0x58, 0xab, 0x35, 0xc0, 0x58, 0xb8, 0x65, 0x40, 0xca,
    0x9b, 0x6c, 0xeb, 0x2f, 0xf5, 0xbf, 0xbd, 0x0b, 0xf3, 0xa6, 0x30, 0x81,
    0x90, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x88, 0x30, 0x81, 0x85,
    0x80, 0x14, 0xe3, 0x58, 0xab, 0x35, 0xc0, 0x58, 0xb8, 0x65, 0x40, 0xca,
    0x9b, 0x6c, 0xeb, 0x2f, 0xf5, 0xbf, 0xbd, 0x0b, 0xf3, 0xa6, 0xa1, 0x62,
    0xa4, 0x60, 0x30, 0x5e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
    0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
    0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e,
    0x63, 0x2e, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
    0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
    0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
    0x55, 0x04, 0x03, 0x13, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
    0x73, 0x74, 0x82, 0x09, 0x00, 0xc2, 0xa8, 0x3b, 0xaa, 0x40, 0xa4, 0x29,
    0x2b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
    0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
    0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x41, 0x40, 0x07,
    0xde, 0x1f, 0xd0, 0x00, 0x62, 0x75, 0x36, 0xb3, 0x94, 0xa8, 0xac, 0x3b,
    0x98, 0xbb, 0x28, 0x56, 0xf6, 0x9f, 0xe3, 0x87, 0xd4, 0xa1, 0x7a, 0x85,
    0xce, 0x40, 0x8a, 0xfd, 0x12, 0xb4, 0x99, 0x8c, 0x1d, 0x05, 0x61, 0xdb,
    0x35, 0xb8, 0x04, 0x7c, 0xfb, 0xe4, 0x97, 0x88, 0x66, 0xa0, 0x54, 0x7b,
    0x1c, 0xce, 0x99, 0xd8, 0xd3, 0x99, 0x80, 0x40, 0x9b, 0xa2, 0x73, 0x8b,
    0xfd
};
static unsigned int cert_der_len = 637;

typedef struct {
    uint32_t session_id;
    bool is_session_resume;
    SSLContextRef st;
    bool is_server;
    bool is_dtls;
    SSLAuthenticate client_side_auth;
    bool dh_anonymous;
    int comm;
    CFArrayRef certs;
    CFArrayRef peer_certs;
    SSLProtocol proto;
    uint64_t time; // output
} ssl_test_handle;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

@implementation STLegacyTests (session)

-(void)test_set_protocol_version
{
    SSLContextRef ctx = NULL;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    SSLProtocol version;
    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersionMin(ctx, &version));
    XCTAssertNotEqual(version, kSSLProtocolUnknown);
    XCTAssertEqual(errSecSuccess, SSLSetProtocolVersionMin(ctx, kTLSProtocol12));
    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersionMin(ctx, &version));
    XCTAssertEqual(version, kTLSProtocol12);

    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersionMax(ctx, &version));
    XCTAssertEqual(version, kTLSProtocol12);
    CFReleaseNull(ctx);
}

-(void)test_set_peer_name
{
    SSLContextRef ctx = NULL;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    const char *peerName = "localhost";
    size_t peerNameLen = strlen(peerName);
    XCTAssertEqual(errSecSuccess, SSLSetPeerDomainName(ctx, peerName, peerNameLen));
    size_t getPeerNameLen;
    
    XCTAssertEqual(errSecSuccess, SSLGetPeerDomainNameLength(ctx, &getPeerNameLen));
    XCTAssertEqual(getPeerNameLen, peerNameLen);
    char *getPeerName = malloc(getPeerNameLen);
    XCTAssertEqual(errSecSuccess, SSLGetPeerDomainName(ctx, getPeerName, &getPeerNameLen));
    free(getPeerName);
    CFReleaseNull(ctx);
}

-(void)test_set_session_ticket
{
    SSLContextRef ctx = NULL;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetSessionTicketsEnabled(ctx, true));
    CFReleaseNull(ctx);
}

-(void)test_set_cert_verify
{
    SSLContextRef ctx;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetEnableCertVerify(ctx, false));
    Boolean enableVerify;
    XCTAssertEqual(errSecSuccess, SSLGetEnableCertVerify(ctx, &enableVerify));
    XCTAssertEqual(false, enableVerify);
    CFReleaseNull(ctx);
}

-(void)test_set_any_root
{
    SSLContextRef ctx;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetAllowsAnyRoot(ctx, false));
    Boolean anyRoot;
    XCTAssertEqual(errSecSuccess, SSLGetAllowsAnyRoot(ctx, &anyRoot));
    XCTAssertEqual(false, anyRoot);
    CFReleaseNull(ctx);
}

-(void)test_set_ca
{
    SSLContextRef serverCtx, clientCtx;
    CFMutableArrayRef certList =  NULL;
    XCTAssert(serverCtx = SSLCreateContext(NULL, kSSLServerSide, kSSLStreamType), "SSLNewContext");
    XCTAssert(clientCtx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    SecCertificateRef cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
                                                           cert_der, cert_der_len);

    XCTAssertEqual(errSecParam, SSLSetCertificateAuthorities(clientCtx, cert, true));
    XCTAssertEqual(errSecSuccess, SSLSetCertificateAuthorities(serverCtx, cert, true));

    certList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
    CFArrayAppendValue(certList, cert);
    XCTAssertEqual(errSecSuccess, SSLSetCertificateAuthorities(serverCtx, certList, true));

    CFArrayRef inputCertList = NULL;
    XCTAssertEqual(errSecSuccess, SSLCopyCertificateAuthorities(serverCtx, &inputCertList));
    CFReleaseNull(inputCertList);
    CFReleaseNull(certList);
    CFReleaseNull(cert);
    CFReleaseNull(serverCtx);
    CFReleaseNull(clientCtx);

}

-(void)test_set_psk_identity
{
    SSLContextRef ctx;
    const uint8_t *pskIdentity;
    size_t pskIdentityLen;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetPSKIdentity(ctx, "Client_identity", 15), "Set PSK Identity");
    XCTAssertEqual(errSecSuccess, SSLSetPSKIdentity(ctx, "Client_identity2", 16), "Set PSK Identity");
    XCTAssertEqual(errSecSuccess, SSLGetPSKIdentity(ctx, (void*)&pskIdentity, &pskIdentityLen), "Get PSK Identity");
    CFReleaseNull(ctx);
}

-(void)test_get_set_ec_curves
{
    SSLContextRef ctx;
    unsigned int numCurves;
    SSL_ECDSA_NamedCurve ecCurve = SSL_Curve_secp256r1;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetECDSACurves(ctx, &ecCurve, 1), "Set EC Curve");
    XCTAssertEqual(errSecSuccess, SSLGetNumberOfECDSACurves(ctx, &numCurves), "Get number of EC curves");
    XCTAssertEqual(numCurves, 1);
    SSL_ECDSA_NamedCurve *namedCurves = malloc(numCurves * sizeof(SSL_ECDSA_NamedCurve));
    SSLGetECDSACurves(ctx, namedCurves, &numCurves);
    XCTAssertEqual(*namedCurves, ecCurve);
    CFReleaseNull(ctx);
}

-(void)test_set_protocol_version_deprecated
{
    SSLContextRef ctx;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, true));
    Boolean enabled;
    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersionEnabled(ctx, kTLSProtocol12, &enabled));
    XCTAssertEqual(enabled, true);
    XCTAssertEqual(errSecSuccess, SSLSetProtocolVersion(ctx, kTLSProtocol12));
    SSLProtocol protocol;
    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersion(ctx, &protocol));
    XCTAssertEqual(protocol, kSSLProtocolAll);
    XCTAssertEqual(errSecSuccess, SSLSetProtocolVersionEnabled(ctx, kTLSProtocol12, true));
    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersionEnabled(ctx, kTLSProtocol12, &enabled));
    XCTAssertEqual(enabled, true);
    XCTAssertEqual(errSecSuccess, SSLSetProtocolVersionEnabled(ctx, kTLSProtocol1, false));
    XCTAssertEqual(errSecSuccess, SSLGetProtocolVersionEnabled(ctx, kTLSProtocol1, &enabled));
    XCTAssertEqual(enabled, false);
    CFReleaseNull(ctx);
}

-(void)test_ssl_error_session
{
    SSLContextRef ctx;
    XCTAssert(ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext");
    XCTAssertEqual(errSecSuccess, SSLSetError(ctx, errSecCertificateRevoked));
    XCTAssertEqual(errSecSuccess, SSLHandshake(ctx));
    CFReleaseNull(ctx);
}

@end

#pragma clang diagnostic pop
